package com.beidasoft.web.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.beidasoft.web.model.system.User;
import com.beidasoft.web.util.Log4jUtil;
import com.beidasoft.web.util.encrypt.EncAndDecProperties;
import com.beidasoft.web.util.encrypt.factory.BDPEncryptFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 拦截所有请求,未登录直接返回到登录页面
 * 控制操作日志
 * Created by Eric on 15/10/15.
 */
@Slf4j
public class CommonInterceptor extends HandlerInterceptorAdapter {


    @Resource
    private BDPEncryptFactory bdpEncryptFactory;

    @Resource
    private EncAndDecProperties encryptProperties;

    @Value("${SSO_TOKEN_USER_INFO}")
    private String tokenUrl;

    @Value("${SSO_LOGIN}")
    private String ssoLogin;
    /**
     * 业务方法拦截前操作
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestUri = request.getRequestURI();
//        String referer = request.getHeader("Referer");
        if (requestUri.equals("/system/specialLogin")) {
            return true;
        }
//        if(referer == null){
//            request.getRequestDispatcher("/login.jsp").forward(request,response);
//            return false;
//        }
        clearXss(request);
        if (requestUri.equals("/system/login")
                || requestUri.equals("/sys/frontLogin")
                || requestUri.equals("/enforceQualification/examineCertApply/personCertCheck")
                || requestUri.equals("/enforceQualification/examineCertApply/newPersonCertCheck")
                || requestUri.equals("/system/validateUserName")
                || requestUri.equals("/system/saveUserInfo")
                || requestUri.equals("/system/Register")
                || requestUri.equals("/system/getUserInfoByToken")
                || requestUri.equals("/system/refindAccount")
                || requestUri.equals("/system/AccountInfoSave")
                || requestUri.equals("/system/generate")
                || requestUri.equals("/enforceQualification/examineCertApply/personQrCode")
                || requestUri.equals("/sys/testPage")
                || requestUri.equals("/powerListManager/powerListManager/queryCodeAndName")
                || requestUri.equals("powerListManager/transferInDeptConfirm/dataTable")
                || requestUri.equals("/system/user/syncUserInfo")
                || requestUri.equals("/examinationManager/enrolmentManager/getEnrolmentPicture")
                || requestUri.equals("/baseManager/lawDeptManager/innerDeptList") //手动启动定时任务
                || requestUri.equals("/checkProcessManager/caseExamineCheck/selectResultListById") //手动启动定时任务
                || requestUri.equals("/checkProcessManager/caseExamineCheck/reFreshSession") //手动启动定时任务
                || requestUri.contains("/statisticalAnalysis/casesSummaryReportTool")
                || requestUri.contains("/inspection/inspectionItem/checkStandardPdf") // 下载检查标准
                || requestUri.contains("/testController/test") // 下载检查标准
                || requestUri.contains("/testController/applyCert")
                || requestUri.equals("/sys/temp")) {// 访问登录直接通过

            return true;
        } else {
            // 当没有用户登录时，判断是否有SSO-TOKEN
             String ssoToken = request.getHeader("SSO-TOKEN") == null ? request.getParameter("SSO-TOKEN") : request.getHeader("SSO-TOKEN");
             if(!StringUtils.isEmpty(ssoToken)) {
                JSONObject userInfo = getUserInfoByTicket(ssoToken);
                if(loginWithSSO(userInfo, request.getSession())) {
                    return true;
                }
            }else{
             }

             if (request.getSession().getAttribute("user") != null) {// 登录过的用户

                 if (request.getSession().getAttribute("isLockScreen") != null) {// 锁屏状态


                    if (requestUri.equals("/system/unlockScreen")) {// 屏幕解锁操作
                         return true;
                    }
                    response.sendRedirect(ssoLogin);
                    return false;
                }
                if (requestUri.equals("/")) {
                    response.sendRedirect(ssoLogin);
                    return false;
                }
                return true;
            }
        }
        // 未登录直接跳转登录页面
//        request.getRequestDispatcher("/login.jsp").forward(request, response);
        response.sendRedirect(ssoLogin);
        return false;
    }

    private JSONObject getUserInfoByTicket(String ssoToken) {
        Map<String, String> header = new HashMap<>();
        header.put("SSO-TOKEN", ssoToken);
        String result = sendPostUrl(tokenUrl, null, header);
         com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(result);
         JSONObject userInfo = null;
        if(jsonObject.getInteger("code") == 200) {
            userInfo = jsonObject.getJSONObject("data");
            if(userInfo != null && !userInfo.isEmpty()) {
                if (org.apache.commons.lang3.StringUtils.isNotBlank(userInfo.getString("idCard"))) {
                    try {
                        String idCard = bdpEncryptFactory.getEncryptStrategyService(encryptProperties.getEncryptType()).decrypt(userInfo.getString("idCard"));
                        userInfo.put("idCard", idCard);
                     } catch (Exception e) {
                        //log.error("身份证解密失败", e);
                        System.out.println("身份证解密失败");
                        userInfo.put("idCard", null);
                        return userInfo;
                    }
                }
            }
        }
        return userInfo;
    }

    private String sendPostUrl(String methodUrl, Object params, Map<String, String> header) {
        HttpURLConnection connection = null;
        BufferedReader reader = null;
        String line;
        StringBuilder result = new StringBuilder();
        try {
            URL url = new URL(methodUrl);
            connection = (HttpURLConnection) url.openConnection();// 根据URL生成HttpURLConnection
            connection.setDoOutput(true);// 设置是否向connection输出，因为这个是post请求，参数要放在http正文内，因此需要设为true,默认情况下是false
            connection.setDoInput(true); // 设置是否从connection读入，默认情况下是true;
            connection.setRequestMethod("POST");// 设置请求方式为post,默认GET请求
            connection.setUseCaches(false);// post请求不能使用缓存设为false
            connection.setConnectTimeout(3000);// 连接主机的超时时间
            connection.setReadTimeout(3000);// 从主机读取数据的超时时间
            connection.setInstanceFollowRedirects(true);// 设置该HttpURLConnection实例是否自动执行重定向
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            connection.setRequestProperty("Content-Type", "application/json");
            for(String key : header.keySet()) {
                connection.setRequestProperty(key, header.get(key));
            }

            OutputStreamWriter paramout = new OutputStreamWriter(
                    connection.getOutputStream(), StandardCharsets.UTF_8);
            connection.connect();// 建立TCP连接,getOutputStream会隐含的进行connect,所以此处可以不要
            if(params != null) {
                paramout.write(params.toString());
            }
            paramout.flush();
            paramout.close();

            if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8));// 发送http请求
                // 循环读取流
                while ((line = reader.readLine()) != null) {
                    result.append(line).append(System.getProperty("line.separator"));
                }
            }
        } catch (IOException e) {
            Log4jUtil.USER_LOG.error(e);
        } finally {
            try {
                if (reader != null)
                    reader.close();
            } catch (IOException e) {
                Log4jUtil.USER_LOG.error(e);
            }
            if (connection != null)
                connection.disconnect();
        }
        return result.toString();
    }

    private boolean loginWithSSO(JSONObject userInfo, HttpSession httpSession) {
        if (userInfo == null) {
            return false;
        }
        try {
            User user = null;


            if (user != null) {

                return true;
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            String exceptionError = "相同用户名存在多个";
            Log4jUtil.USER_LOG.error(exceptionError, e);
        }
        return false;
    }

    /**
     * 业务操作之后
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

    /**
     * 过滤请求数据中的恶意字符
     *
     * @param request
     * @throws Exception
     */
    private void clearXss(HttpServletRequest request) throws Exception {
        Enumeration<String> attributeNames = request.getAttributeNames();
        Object key = "";
        while (attributeNames.hasMoreElements()) {
            key = attributeNames.nextElement();
            if (request.getAttribute(key.toString()) != null && request.getAttribute(key.toString()) instanceof String) {
                request.setAttribute(key.toString(), cleanXSS(request.getAttribute(key.toString()).toString()));
            }
        }
    }

    /**
     * 清理XSS
     *
     * @param value
     * @return
     */
    private String cleanXSS2(String value) {
        value = value.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
        value = value.replaceAll("\\(", "&#40;").replaceAll("\\)", "&#41;");
        value = value.replaceAll("'", "&#39;");
        value = value.replaceAll("eval\\((.*)\\)", "");
        value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
        return value;
    }

    /**
     * 清理XSS
     *
     * @param value
     * @return
     */
    private String cleanXSS(String value) {
        if (value != null) {
            //推荐使用ESAPI库来避免脚本攻击,value = ESAPI.encoder().canonicalize(value);
            // 避免空字符串
            value = value.replaceAll(" ", "");
            // 避免script 标签
            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免src形式的表达式
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // 删除单个的 </script> 标签
            scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            // 删除单个的<script ...> 标签
            scriptPattern = Pattern.compile("<script(.*?)>",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 eval(...) 形式表达式
            scriptPattern = Pattern.compile("eval\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 e­xpression(...) 表达式
            scriptPattern = Pattern.compile("e­xpression\\((.*?)\\)",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 javascript: 表达式
            scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 vbscript:表达式
            scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");
            // 避免 οnlοad= 表达式
            scriptPattern = Pattern.compile("onload(.*?)=",
                    Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
        }
        return value;
    }
}

